package net.cs.rm;

import java.beans.PropertyDescriptor;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.hibernate.EntityMode;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import dao.hb.*;

import net.bat.db.BaseDAO;
import net.bat.service.IHandle;
import net.bat.task.Task;
import net.bat.task.TaskCenter;
import net.bat.upload.uploadServlet;
import net.cs.um.UMService;

public class RMService implements IHandle {
	public static final char METHOD_JSON = 'J';
	public static final char METHOD_COPYMNU = 'C';
	public static final char METHOD_SORT = 'S';
	public static final char METHOD_CY = 'Y';
	
	//数据库操作通用对象
	static private BaseDAO dao;

	public BaseDAO getDao() {
		return dao;
	}

	public void setDao(BaseDAO dao) {
		this.dao = dao;
	}
	public String copyMenu(HashMap<String, Object> req,HttpServletRequest request) throws Exception{
		String tid = (String)req.get("tid");
		String rtid = (String)req.get("rtid");
		UUser usr = UMService.getUserBySession(request);
		NBase nb_rt = (NBase)dao.loadPO("dao.hb.NBase",rtid);
		if(nb_rt==null || !nb_rt.getUid().equals(usr.getId())){
			throw new Exception("非法的目标条目");
		}
		Object[] ids = (Object[])req.get("ids");
		Task task = TaskCenter.getTask(tid);
		task.setTotal(ids.length);
		//记录菜品NBase节点新旧id映射
		HashMap<Integer,Integer>idmap = new HashMap<Integer,Integer>();
		//step1 应先保存tnid 为空的主节点
		int cur=0;
		List<NBase> ls_tn = new ArrayList<NBase>();
		for(int i=0; i<ids.length; i++){
			NBase nb_mnu =(NBase)dao.loadPO("dao.hb.NBase", ids[i].toString());
			//翻译菜品，稍后处理
			if(nb_mnu.getTnid()!=null){
				ls_tn.add(nb_mnu);
				continue;
			}
			task.setInfo("copying NBase["+nb_mnu.getId()+"]");
			copyItem(nb_rt,nb_mnu,idmap,usr.getId(),nb_rt.getId());
			cur++;
			task.setCur(cur);
		}
		//step2 然后保存tnid不为空的节点,以确保tnid指向的NBase已经处理,其新旧id映射在idmap中
		for(int i=0; i<ls_tn.size(); i++){
			NBase nb_mnu = ls_tn.get(i);
			task.setInfo("copying NBase["+nb_mnu.getId()+"]");
			NBase pnb_mnu = copyItem(nb_rt,nb_mnu,idmap,usr.getId(),nb_rt.getId());
			//设置新的翻译节点,如果不存在,则设为null
			pnb_mnu.setTnid(idmap.get(pnb_mnu.getTnid()));
			dao.update(pnb_mnu);
			cur++;
			task.setCur(cur);
		}
		TaskCenter.done(tid);
		return null;
	}
	//TODO copy menu item, related tranlated item & attach items to target restaurant
	//翻译节点
	private NBase copyItem(NBase targetRT, NBase nb,HashMap<Integer,Integer>idmap,int uid,int rid){
		//克隆菜品主节点
		NBase pnb = (NBase)cloneObj(nb,uid);
		//菜品主节点指向餐馆主节点
		pnb.setPnid(rid);
		dao.save(pnb);
		//记住新旧关联
		idmap.put(nb.getId(), pnb.getId());
		//克隆NMenu
		NMenu nr = (NMenu)dao.get("from NMenu where id=?", new Object[]{nb.getVid()});
		if(nr==null){
			return pnb;
		}
		NMenu pnr = (NMenu)cloneObj(nr,uid);
		//NMenu指向主节点
		pnr.setNid(pnb.getId());
		dao.save(pnr);
		//更新主节点版本
		pnb.setVid(pnr.getId());
		dao.update(pnb);
				
		//克隆图片附件节点
		//TODO 可能造成附件覆盖？
		List ls = dao.find("from NBase where pnid=?",new Object[]{nb.getId()});
		for(int i=0; i<ls.size(); i++){
			NBase na = (NBase)ls.get(i);
			NBase pna = (NBase)cloneObj(na,uid);
			pna.setPnid(pnb.getId());
			dao.save(pna);
			//克隆NImage
			NImage ni = (NImage)dao.get("from NImage where id=?", na.getVid());
			if(ni==null){
				continue;
			}
			NImage pni = (NImage)cloneObj(ni,uid);
			//NImage指向主节点
			pni.setNid(pna.getId());
			dao.save(pni);
			//更新主节点版本
			pna.setVid(pni.getId());
			dao.update(pna);
		}
		return pnb;
	}
	private Object cloneObj(Object so,int uid){
		ClassMetadata cm=dao.getClassMeta(so.getClass().getName());		
		Object po = cm.instantiate(null,EntityMode.POJO);
		BeanWrapper bs = new BeanWrapperImpl(so);
		BeanWrapper bp = new BeanWrapperImpl(po);
		PropertyDescriptor[] ps = bs.getPropertyDescriptors();
		for(int i=0; i<ps.length; i++){
			String pn = ps[i].getName();
			if(bp.isWritableProperty(pn)){
				if(pn.equals("uid")){
					//用户id取本人
					bp.setPropertyValue(pn, uid);
				}else {
					bp.setPropertyValue(pn, bs.getPropertyValue(pn));
				}
			}
		}
		return po;
	}
	
	public String toJSon(HashMap<String, Object> req,HttpServletRequest request) throws Exception{
		String filter = (String)req.get("filter");
		if(filter==null){
			UUser usr = UMService.getUserBySession(request);
			filter = "from NBase where itype="+JSonOut.TYPE_NODE_RESTAURANT
					+ " and uid="+usr.getId()+" and language='"+usr.getLang()+"'";
		}
		String tid = (String)req.get("tid");
		boolean bcover = (Boolean)req.get("bcover");
		JSonOut jo = new JSonOut(filter,tid);
		return jo.toJSon(bcover);
	}
	public String cy(HashMap<String, Object> req,HttpServletRequest request) throws Exception{
		Integer sid = (Integer)req.get("id");
		String scn = (String)req.get("scn");
		String tcn = (String)req.get("tcn");
		Object sobj = dao.loadPO(scn,sid.toString());
		ClassMetadata cm=dao.getClassMeta(tcn);		
		Object tobj = cm.instantiate(null,EntityMode.POJO);
		UUser usr = UMService.getUserBySession(request);
		copyPropVal(sobj,tobj,usr.getId());
		dao.save(tobj);
		BeanWrapper bwt = new BeanWrapperImpl(tobj);
		return bwt.getPropertyValue("id")+"";
	}
	private void copyPropVal(Object sobj, Object tobj,int uid){
		BeanWrapper bws = new BeanWrapperImpl(sobj);
		BeanWrapper bwt = new BeanWrapperImpl(tobj);
		PropertyDescriptor[] ps = bws.getPropertyDescriptors();
		Date dt = new Date();
		for(int i=0; i<ps.length; i++){
			PropertyDescriptor p = ps[i];
			String pn = p.getName();
			if(pn.equals("uid")){
				bwt.setPropertyValue(pn, uid);
				continue;
			}
			if(pn.equals("dtCreate")){
				bwt.setPropertyValue(pn, dt);
				continue;
			}
			if(!pn.equals("id") && bwt.isWritableProperty(pn)){
				bwt.setPropertyValue(pn, bws.getPropertyValue(pn));
			}
		}
		bwt.setPropertyValue("status", 1);
	}
	public String sortMenu(HashMap<String, Object> req,HttpServletRequest request) throws Exception{
		Integer nid = (Integer)req.get("nid");
		UUser usr = UMService.getUserBySession(request);
		NBase nb_rt = (NBase)dao.loadPO("dao.hb.NBase",nid.toString());
		if(nb_rt==null || !nb_rt.getUid().equals(usr.getId())){
			throw new Exception("非法的目标条目");
		}
		List ls = dao.find("from NSort where nid=?", new Object[]{nid});
		HashMap<Integer,List> cldMap = new HashMap<Integer,List> ();
		for(int i=0; i<ls.size(); i++){
			NSort cur = (NSort)ls.get(i);
			Integer pid = cur.getPid();
			if(pid!=null){
				List clds = cldMap.get(pid);
				if(clds==null){
					clds = new ArrayList();
					cldMap.put(pid, clds);
				}
				clds.add(cur);
			}
		}
		StringBuffer sbuf = new StringBuffer();
		sbuf.append("Ext.data.JsonP.feedCb({\"lists\":[\n");
		for(int i=0; i<ls.size(); i++){
			NSort cur = (NSort)ls.get(i);
			List clds = cldMap.get(cur.getId());
			if(clds==null){
				continue;
			}
			if(i>0){
				sbuf.append( ",");
			}
			sbuf.append( "{\"text\":\"");
			sbuf.append(cur.getTitle());
			sbuf.append("\",\n\"checked\": false,\n\"leaf\": false,\n\"children\":[");
			for(int j=0; j<clds.size(); j++){
				NSort cld = (NSort)clds.get(j);
				if(j>0){
					sbuf.append( ",");
				}
				sbuf.append( "{\"text\":\"");
				sbuf.append(cld.getTitle());
				sbuf.append("\",\n\"checked\": false,\n\"leaf\": true,\n}");
			}
			sbuf.append("\n]}");
		}
		sbuf.append("]});");
		//write to file
		String fpath = usr.getId()+File.separator+"json";
		uploadServlet.makeDir(fpath,JSonOut.PATH_JSON, false);
		//翻译餐馆取母语id
		if(nb_rt.getTnid()!=null){
			nid=nb_rt.getTnid();
		}
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
				new FileOutputStream(JSonOut.PATH_JSON+fpath+File.separatorChar
						+nid+"_"+nb_rt.getLanguage()+"_cls.json"), "utf-8"));

		bw.write(sbuf.toString());
		bw.close();
		return null;
	}

	@Override
	public Object handle(char method, HashMap<String, Object> rm,
			HttpServletRequest request) throws Exception {
		// TODO Auto-generated method stub
		switch(method){
		case METHOD_JSON:
			return toJSon(rm,request);
		case METHOD_COPYMNU:
			return copyMenu(rm,request);
		case METHOD_SORT:
			return sortMenu(rm,request);
		case METHOD_CY:
			return cy(rm,request);
		}
		return null;
	}

}
